package com.bsj.travel.filter;

import com.alibaba.fastjson2.JSON;
import com.bsj.travel.cached.redis.RedisCached;
import com.bsj.travel.config.properties.IgnoreGeneralProperties;
import com.bsj.travel.constant.Constants;
import com.bsj.travel.constant.SecurityConstants;
import com.bsj.travel.def.common.VO.TokenUser;
import com.bsj.travel.def.global.JsonResult;
import com.bsj.travel.def.global.JsonResultEnum;
import com.bsj.travel.util.SecurityUtils;
import com.bsj.travel.util.ServletUtils;
import com.bsj.travel.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * @author yinhao
 * @version 1.0
 * @description 网关鉴权
 * @date 2023/10/18
 */
@Component
@Slf4j
public class AuthFilter implements GlobalFilter, Ordered {

    @Autowired
    private IgnoreGeneralProperties ignoreProperties;

    @Autowired
    private RedisCached redisCached;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpRequest.Builder mutate = request.mutate();
        String url = request.getURI().getPath();
        //跳过不需要验证的请求
        if (StringUtils.matches(url, ignoreProperties.getGeneral())) {
            return chain.filter(exchange);
        }
        //获取请求token
        String authToken = request.getHeaders().getFirst(SecurityConstants.TOKEN_AUTH);
        String token = SecurityUtils.replaceTokenPrefix(authToken);
        if (org.apache.commons.lang3.StringUtils.isEmpty(token)) {
            return unAuthResponse(exchange, JsonResult.fail(JsonResultEnum.NOT_AUTH_ISNULL));
        }
        //无效的登录状态
        String userToken = redisCached.get(Constants.LOGIN_TOKEN_KEY + token);
        if (org.apache.commons.lang3.StringUtils.isEmpty(userToken)) {
            return unAuthResponse(exchange, JsonResult.fail(JsonResultEnum.USER_LOGIN_AUTH_NULL));
        }
        TokenUser tokenUser = JSON.parseObject(userToken, TokenUser.class);
        //TODO 增加用户ID判断

        //需要给使用的token设置过期时间,三小时过期
        redisCached.expire(Constants.LOGIN_TOKEN_KEY + token, 180 * 60);
        //设置用户信息到请求中
        addHeader(mutate, SecurityConstants.USER_ID, tokenUser.getUserId());
        addHeader(mutate, SecurityConstants.USER_NAME, "userName");
        //内部请求来源参数清除
        removeHeader(mutate, SecurityConstants.FROM_SOURCE);
        return chain.filter(exchange.mutate().request(mutate.build()).build());
    }

    /**
     * 设置过滤器的优先级，值越小优先级越高
     * @return
     */
    @Override
    public int getOrder() {
        return -200;
    }

    private Mono<Void> unAuthResponse(ServerWebExchange exchange, JsonResult result) {
        log.info("[网关鉴权异常]请求路径: {}", exchange.getRequest().getPath());
        return ServletUtils.webFluxResponseWriter(exchange.getResponse(), result, HttpStatus.UNAUTHORIZED.value());
    }

    private void addHeader(ServerHttpRequest.Builder mutate, String name, Object value) {
        if (value == null) {
            return;
        }
        String valueEncode = ServletUtils.urlEncode(value.toString());
        mutate.header(name, valueEncode);
    }

    private void removeHeader(ServerHttpRequest.Builder mutate, String name) {
        mutate.headers(httpHeaders -> httpHeaders.remove(name)).build();
    }
}
